package cn.tedu.aiumall.user.webapi.service.impl;


import cn.tedu.aiumall.common.pojo.user.dto.UserAddNewDTO;
import cn.tedu.aiumall.common.pojo.user.dto.UserLoginDTO;
import cn.tedu.aiumall.common.pojo.user.entity.User;
import cn.tedu.aiumall.common.pojo.user.entity.UserRole;
import cn.tedu.aiumall.common.pojo.user.vo.UserLoginInfoVO;
import cn.tedu.aiumall.user.service.IUserService;
import cn.tedu.aiumall.user.webapi.ex.ServiceCode;
import cn.tedu.aiumall.user.webapi.ex.ServiceException;
import cn.tedu.aiumall.user.webapi.mapper.UserMapper;
import cn.tedu.aiumall.user.webapi.mapper.UserRoleMapper;
import cn.tedu.aiumall.user.webapi.security.UserDetails;

import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;

@Slf4j
@Service
public class UserServiceImpl implements IUserService {
    public static String sendMessage;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private UserRoleMapper userRoleMapper;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Value("fg1dasfa6e5g165ADSGFSADG5sfaf")
    private String secureKey;
    @Value("10000")
    private Long durationInMinute;

    @Override
    public void addNew(UserAddNewDTO userAddNewDTO) {
        log.info("开始处理添加用户");
        String username = userAddNewDTO.getUsername();
        int result = userMapper.countByUsername(username);
        if (result != 0) {
            String message = "抱歉您输入的用户名" + username + "已经被注册了";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }
        String phone = userAddNewDTO.getPhone();
        int phone1 = userMapper.countByPhone(phone);
        if (phone1 != 0) {
            String message = "抱歉您输入的手机号" + phone + "已经被注册了";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }
        String email = userAddNewDTO.getEmail();
        int email1 = userMapper.countByEmail(email);
        if (email1 != 0) {
            String message = "抱歉您输入的邮箱" + email + "已经被注册了";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        User user = new User();
        BeanUtils.copyProperties(userAddNewDTO, user);
        //设置启用
        user.setIsEnable(1);
        String rawPassword = user.getPassword();
        String encodedPassword = passwordEncoder.encode(rawPassword);
        user.setPassword(encodedPassword);
        log.info("即将插入数据");
        int insert = userMapper.insert(user);
        log.info("插入数据成功");
        if (insert != 1) {
            String message = "服务器异常,请稍后重试";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }
        LocalDateTime now = LocalDateTime.now();
        List<UserRole> userRoleList = new ArrayList<>();
        for (int i = 0; i < 1; i++) {
           UserRole userRole = new UserRole();
           userRole.setUserId(user.getId());
           userRole.setRoleId(1L);
            userRole.setGmtCreate(now);
            userRole.setGmtModified(now);
            userRoleList.add(userRole);
        }
        result =userRoleMapper.insertBatch(userRoleList);
        if (result!=1){
            String message = "添加管理员失败，服务器忙，请稍后再尝试！[错误代码：3]";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }

    }




    @Override
    public String login(UserLoginDTO userLoginDTO) {
        log.info("开始处理【登录认证】的业务，参数：{}", userLoginDTO);
        UserLoginInfoVO UsernameOrPhoneOrEmail = userMapper.getStandardByUsernameOrPhoneOrEmail(userLoginDTO.getUsernameOrPhoneOrEmail());
       log.info("开始处理【登录认证】的业务，参数：{}", UsernameOrPhoneOrEmail);
        String username = UsernameOrPhoneOrEmail.getUsername();
        log.info("开始处理【登录认证】的业务，参数：{}", username);
        // 调用AuthenticationManager的authenticate()方法执行认证
        // 在authenticate()方法的执行过程中
        // Spring Security会自动调用UserDetailsService对象的loadUserByUsername()获取用户详情
        // 并根据loadUserByUsername()返回的用户详情自动验证是否启用、判断密码是否正确等
        Authentication authentication
                = new UsernamePasswordAuthenticationToken(
                username,
                userLoginDTO.getPassword());
        Authentication authenticateResult
                = authenticationManager.authenticate(authentication);
        log.info("Spring Security已经完成认证，且认证通过，返回的结果：{}", authenticateResult);
        log.info("返回认证信息中的当事人（Principal）类型：{}", authenticateResult.getPrincipal().getClass().getName());
        log.info("返回认证信息中的当事人（Principal）数据：{}", authenticateResult.getPrincipal());

        // 从认证返回结果中取出当事人信息
        UserDetails principal = (UserDetails) authenticateResult.getPrincipal();
        Long id = principal.getId();
        log.info("认证信息中的用户id：{}", id);
        username = principal.getUsername();
        log.info("认证信息中的用户名：{}", username);
        Collection<GrantedAuthority> authorities = principal.getAuthorities();
        log.info("认证信息中的权限：{}", authorities);
        String authorityListString = JSON.toJSONString(authorities);
        log.info("认证信息中的权限转换为JSON字符串：{}", authorityListString);

        // 生成JWT，并返回
        // 准备Claims值
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", id);
        claims.put("username", username);
        claims.put("authorities", authorityListString);

        // JWT的过期时间
        Date expiration = new Date(System.currentTimeMillis() + durationInMinute * 60 * 1000);
        log.info("即将生成JWT数据，过期时间：{}", expiration);

        // JWT的组成：Header（头：算法和Token类型）、Payload（载荷）、Signature（签名）
        String jwt = Jwts.builder()
                // Header
                .setHeaderParam("alg", "HS256")
                .setHeaderParam("typ", "JWT")
                // Payload
                .setClaims(claims)
                .setExpiration(expiration)
                // Signature
                .signWith(SignatureAlgorithm.HS256, secureKey)
                .compact();
        log.info("已经生成JWT数据：{}", jwt);
        return jwt;
    }


}


